package org.yaac.server.conf;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;

import org.yaac.shared.stat.models.Kind;
import org.yaac.shared.stat.models.KindIsRootEntity;
import org.yaac.shared.stat.models.KindNonRootEntity;
import org.yaac.shared.stat.models.NSKind;
import org.yaac.shared.stat.models.NSKindIsRootEntity;
import org.yaac.shared.stat.models.NSKindNonRootEntity;
import org.yaac.shared.stat.models.NSPropertyNameKind;
import org.yaac.shared.stat.models.NSPropertyType;
import org.yaac.shared.stat.models.NSPropertyTypeKind;
import org.yaac.shared.stat.models.NSPropertyTypePropertyNameKind;
import org.yaac.shared.stat.models.NSTotal;
import org.yaac.shared.stat.models.PropertyNameKind;
import org.yaac.shared.stat.models.PropertyType;
import org.yaac.shared.stat.models.PropertyTypeKind;
import org.yaac.shared.stat.models.PropertyTypePropertyNameKind;
import org.yaac.shared.stat.models.Total;

import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.inject.Injector;
import com.googlecode.objectify.ObjectifyService;

/**
 * This facade is used to process 
 * 
 * @author Max Zhu (thebbsky@gmail.com)
 *
 */
public class GWTRPCFacadeServlet extends RemoteServiceServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * guice injector
	 */
	private final Injector injector;

	private final Logger logger;
	
	@Inject
	GWTRPCFacadeServlet(Injector injector, Logger logger) {
		this.injector = injector;
		this.logger = logger;
		
		// register Objectify classes on server instance start
		ObjectifyService.register(Total.class);
		ObjectifyService.register(NSTotal.class);
		ObjectifyService.register(Kind.class);
		ObjectifyService.register(NSKind.class);
		ObjectifyService.register(KindIsRootEntity.class);
		ObjectifyService.register(NSKindIsRootEntity.class);
		ObjectifyService.register(KindNonRootEntity.class);
		ObjectifyService.register(NSKindNonRootEntity.class);
		ObjectifyService.register(PropertyType.class);
		ObjectifyService.register(NSPropertyType.class);
		ObjectifyService.register(PropertyTypeKind.class);
		ObjectifyService.register(NSPropertyTypeKind.class);
		ObjectifyService.register(PropertyNameKind.class);
		ObjectifyService.register(NSPropertyNameKind.class);
		ObjectifyService.register(PropertyTypePropertyNameKind.class);
		ObjectifyService.register(NSPropertyTypePropertyNameKind.class);	
	}

	/* (non-Javadoc)
	 * @see com.google.gwt.user.server.rpc.RemoteServiceServlet#processCall(java.lang.String)
	 * 
	 */
	@Override
	public String processCall(String payload) throws SerializationException {
		//http://forum.springsource.org/archive/index.php/t-54931.html process request
		try { 
			RPCRequest req = RPC.decodeRequest(payload, null, this);

			RemoteService service = (RemoteService) injector.getInstance(req
					.getMethod().getDeclaringClass());
			
			long start = System.currentTimeMillis();
			logger.info("Processing incoming request for " + service.getClass() + "." + req.getMethod());
			
			String result = RPC.invokeAndEncodeResponse(service, req.getMethod(),
					req.getParameters(), req.getSerializationPolicy());
			
			long end = System.currentTimeMillis();
			logger.info("Finished processing in " + (end - start) + " ms");
			
			return result;
		} catch (IncompatibleRemoteServiceException ex) {
			log("Exception in the processCall(String) method.", ex);
			
			logger.log(Level.SEVERE, "Exception in the processCall(String) method.", ex);
			
			return RPC.encodeResponseForFailure(null, ex);
		}
	}

}
